/* Any Bug U Find In This Code Contact Author
*
*
* This Header File Contains Huffman Decompression Code
*
*
*
*  Author : Vishwajeet C. Dusane(dusanevishwajeet@yahoo.co.in)
*/

#include"Declare.h"
#include"Tree.h"
#include"FileReaderWriter.h"

class HuffDecompress
{
 //variable
  private :

   			 //Block of local variables used in Decompression
			  int fpW,fpR;
			  unsigned int byt_read,chr_depth,chk_depth;
  			  unsigned long chr_code,chk_code,comp_code;
			  unsigned int temp_file_size=0,temp_chr_code=0;
			  unsigned int rem_code,temp_chk=0,prev=0,mult,temp_code=0;
			  unsigned int temp_header_size;
			  int cnt,x,byte_cnt,rem_depth,i,j;
			  unsigned long org_file_size=0,total_node=0,new_file_size=0;
			  unsigned long tmp=0,rem=0,header_size=0;
			  char *ch,fnmW[20],*comp_file_ext,chr,*comp_byte,uch,lch;
			  struct header *head=NULL,*temp;

//=============================================================================

//method
  private:
            unsigned long excedify(unsigned long );
 //variable
  public:
             FileReaderWriter fin;
 //method
 public:
       int decompress(char [15]);


};


//=============================================================================
//This function is Used for converting the Exceding Number
//i.e. Number which is greater then 127
unsigned long HuffDecompress::excedify(no)
unsigned long no;
{
	int rem;
	if(no>ENO)
	{
		rem=no-ENO;
		no=128+rem;
	}
	if(no==ENO)
		no=128;
  return(no);
}


//=============================================================================
int HuffDecompress::decompress(char fnmR[15])
{

  if(fin.openForRead(fnmR[15]))
  {
     printf("\n %s File cann't be open",fnmR);
     exit(0);
  }
  else
  {
    //Reading the TotalNos of Node for header of from Input File
    ch=(char *)malloc(1);
    ch=fin.readInFile();
    tmp=(unsigned int) (*ch);
    tmp=excedify(tmp);
    tmp=tmp<<8;
    tmp=tmp>>8;
    total_node=tmp;

    ch=(char *)malloc(1);
     ch=fin.readInFile();
    tmp=(unsigned int) (*ch);
    tmp=excedify(tmp);
    tmp=tmp<<8;
    tmp=tmp>>8;
    if(total_node!=0)
    {
      total_node=total_node<<8;
      total_node=total_node|tmp;
    }
    else
     total_node=tmp;
    //End of reading TotalNos. of Nodes
//=============================================================================
    //Reading the extension of Original File
    comp_file_ext=(char *)malloc(4);
     ch=fin.readInFile(3);
    comp_file_ext[3]='\0';
    if(strcmp(comp_file_ext,"svv")==0)
	    comp_file_ext=NULL;
    //End of reading Extension
//=============================================================================
    //Read Original File size from Input File
    org_file_size=0;
    temp_file_size=0;
    byte_cnt=3;

    while(byte_cnt>=0)
    {
      ch=(char *)malloc(1);
      ch=fin.readInFile();
      temp_file_size=(unsigned int)(*ch);
      temp_file_size=excedify(temp_file_size);
      temp_file_size=temp_file_size<<8;
      temp_file_size=temp_file_size>>8;

      org_file_size=org_file_size<<8;
      org_file_size=org_file_size|temp_file_size;
      temp_file_size=0;

      byte_cnt=byte_cnt-1;
    }
    //End of Reading Original File size
//=============================================================================
    //Reading Header size from Input File
    header_size=0;
    temp_header_size=0;
    byte_cnt=3;

    while(byte_cnt>=0)
    {
      ch=(char *)malloc(1);
       ch=fin.readInFile();
      temp_header_size=(unsigned int)(*ch);
      temp_header_size=excedify(temp_header_size);
      temp_header_size=temp_header_size<<8;
      temp_header_size=temp_header_size>>8;

      header_size=header_size<<8;
      header_size=header_size|temp_header_size;
      temp_header_size=0;

      byte_cnt=byte_cnt-1;
    }
    //End of reading header size
//=============================================================================
    //Each Header node has sequence as
    //1 bytes char 1 bytes depth and next bytes code
    //Reading one by one and constructing Header Node and Header
    byt_read=0;
    chr_code=0;
    while(header_size>byt_read)
    {
      //Readinng Character
      ch=(char *)malloc(1);
       ch=fin.readInFile();
      chr=(char)(*ch);
      free(ch);

      //increase nos of bytes read
      byt_read=byt_read+1;

      //Reading Depth
      ch=(char *)malloc(1);
       ch=fin.readInFile();
      chr_depth=(unsigned int)(*ch);

      //increase nos of bytes read
      byt_read=byt_read+1;

      //calculate code bytes
      if(chr_depth>8)
      {
	cnt=chr_depth/8;
	if ((chr_depth%8)>0)
	  cnt=cnt+1;

	//Reading code bytes
	for(cnt=cnt-1;cnt>=0;cnt--)
	{
	 ch=(char *)malloc(1);
	  ch=fin.readInFile();
	 byt_read=byt_read+1;
	 temp_chr_code=(unsigned int)(*ch);
	 temp_chr_code=excedify(temp_chr_code);
	 temp_chr_code=temp_chr_code<<8;
	 temp_chr_code=temp_chr_code>>8;
	 chr_code=chr_code<<8;
	 chr_code=chr_code|temp_chr_code;
	}
      }
      //end of Depth > 8
      else
      {
        ch=(char *)malloc(1);
        ch=fin.readInFile();
        byt_read=byt_read+1;
	chr_code=(unsigned int)(*ch);
	chr_code=excedify(chr_code);
        chr_code=chr_code<<8;
	chr_code=chr_code>>8;
      }
      //end of depth <= 8
      chr_code=chr_code<<(16-chr_depth);
      chr_code=chr_code>>(16-chr_depth);
      //Reconstructing Header
      reconstruct_header(&head,chr,chr_code,chr_depth);
      chr_code=0;
    }

    if(head->tot_node != total_node)
    {
       printf("\nFail Header is Corrupted");
       exit(0);
    }
    //End of creation of header
//==============================================================================
    //Start to constuct New file
    //Construct file name for New file
    sscanf(fnmR,"%[^.]s",fnmW);
    strcat(fnmW,"1");
    if(comp_file_ext!=NULL)
    {
     strcat(fnmW,".");
     strcat(fnmW,comp_file_ext);
    }
    if(openForWrite(fnmW))
    {
       printf("New File Opening Error");
       exit(0);
    }
    else
    {
     comp_byte=(char *)malloc(1);
     chk_depth=0;

     while(1)
     {
      //Read Each compressed byte from Input File and
      //Convert to  appropriate character
       x=fin.readInFile();

      if(x==0)//End of Input File : Terminating Condition
       break;

      comp_code=0;
      rem=0;
      //Convert read byte to code and check
      comp_code=(unsigned int)(*comp_byte);
      comp_code=excedify(comp_code);
      comp_code=comp_code<<8;
      comp_code=comp_code>>8;
      cnt=7;
      //Construct check code
      if(chk_depth!=0)
      {
       chk_code=excedify(chk_code);
       chk_code=chk_code<<8;
       chk_code=excedify(chk_code);
       chk_code=chk_code|comp_code;
       chk_code=excedify(chk_code);
       cnt=cnt+chk_depth;
       comp_code=chk_code;
       chk_depth=0;
      }
      while(cnt>=0)
      {
       chk_code=excedify(chk_code);
       chk_code=comp_code>>cnt;
       chk_code=excedify(chk_code);
       chk_depth=chk_depth+1;
       temp_chk=chk_code;
       temp_chk=excedify(temp_chk);
       //Check check code with Header Nodes
       temp=head;
       while(temp!=NULL)
       {
	if(temp->code==temp_chk && temp->depth==chk_depth)
	{
	 *ch=temp->ch;
	 //Cheacking the new File size with Original File
	 //Terminate accordingly if equal
	 if(new_file_size==org_file_size)
	 {
	    printf("\nFile is Uncompressed Successfully with %s name\n",fnmW);
	    fcloseall();
	    return(0);
	 }
	 //Writing matching character to New file
	 if(fin.writeIntoOutFile(ch,1)!=1)
	 {
	   printf("\nFile Writting Error");
	   exit(0);
	 }
	 else
	 {
           //Retriving remaining code form check code
           temp_code=comp_code;
           prev=0;
           mult=1;
           for(i=0;i<cnt;i++)
           {
             rem=temp_code&1;
             temp_code=temp_code>>1;
             mult=1;
             for(j=i;j>0;j--)
             {
               mult=mult*2;
             }
             prev=prev+(rem*mult);
           }

           comp_code=prev;
           prev=0;
	   comp_code=excedify(comp_code);
	   chk_code=0;
	   chk_depth=0;
	   //Keep Track of new File size
	   new_file_size=new_file_size+1;
	 }
	 break;
	}
	//End of if depth & code cheaking
	temp=temp->next;
       }
       //End of head temp while
       cnt--;
      }
      //End of while cnt>0
     }
     //End of while(1)
    }
    //End of else of writting new file
  }
  //End of else of file open fnmR
  fcloseall();
 return 0;
}
//End of Decompression of Input File
